home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Libraries / VideoToolbox 97.08.16 / VideoToolboxSources / SetPixelsQuickly.c < prev    next >
Encoding:
Text File  |  1997-08-16  |  24.0 KB  |  731 lines  |  [TEXT/CWIE]

  1. /*
  2. SetPixelsQuickly.c
  3. All the Set... routines poke a row of pixels.
  4. All the Get... routines peek a row of pixels.
  5. SetPixelsQuickly and GetPixelsQuickly use the current port.
  6. SetWindowPixelsQuickly and GetWindowPixelsQuickly use the supplied window.
  7. SetDevicePixelsQuickly and GetDevicePixelsQuickly use the supplied video device.
  8. SetPixmapPixelsQuickly and GetPixmapPixelsQuickly use the supplied pix/bitmap.
  9.  
  10. int SetPixelsQuickly(int x,int y,unsigned long value[],short n);
  11. int GetPixelsQuickly(int x,int y,unsigned long value[],short n);
  12. int SetWindowPixelsQuickly(WindowPtr window,int x,int y,unsigned long value[],short n);
  13. int GetWindowPixelsQuickly(WindowPtr window,int x,int y,unsigned long value[],short n);
  14. int SetDevicePixelsQuickly(GDHandle device,int x,int y,unsigned long value[],short n);
  15. int GetDevicePixelsQuickly(GDHandle device,int x,int y,unsigned long value[],short n);
  16. int SetPixmapPixelsQuickly(PixMapPtr pmPtr,int x,int y,unsigned long value[],short n);
  17. int GetPixmapPixelsQuickly(PixMapPtr pmPtr,int x,int y,unsigned long value[],short n);
  18.  
  19. This is the fastest and easiest way to transform back and forth between a PixMap
  20. or BitMap and a numerical representation of an arbitrary image amenable to
  21. computation in C. You can think of these routines as replacements for the
  22. official Apple SetCPixel, etc. Their virtue is that they're very fast and don't
  23. translate your index via any color table. Set... and Get... ignore the color
  24. spec arrays, giving you direct access to the unsigned number stored in each
  25. pixel (whether 1, 2, 4, 8, 16, or 32 bits). With appropriate casting you may
  26. supply a CWindowPtr in place of the WindowPtr, and you may supply a BitMapPtr in
  27. place of the PixMapPtr.
  28.  
  29. For all the routines, you supply the (x,y) coordinate of the first pixel you
  30. want to access in the appropriate coordinate system, an unsigned long array
  31. called "value", and the number of pixels to access. x will increment for each
  32. successive pixel. Set... will copy values, one by one, from "value" into the
  33. pix/bitmap. Get... will copy from the pix/bitmap into "value". The routines work
  34. with all pixel sizes: 1 to 32 bits. The "value" array that you supply is 
  35. unsigned long.
  36.  
  37. All the routines clip to enforce either the pix/bitmap's bounds, or the window's
  38. portRect (if you pass a window or use the current window/port). The only way of
  39. getting into trouble would be to pass a window's PixMap directly. It is
  40. difficult to figure out the clipping of a window's PixMap; RectToAddress does
  41. it, but only on the first call, after which we use the old cached answer, which
  42. doesn't include clipping information.
  43.  
  44. The returned value of the function is normally zero, indicating success, but
  45. will be nonzero if the request could not be fully satisfied. All the routines
  46. clip to the bit/pixmap bounds; this is treated as normal by the Set... routines
  47. and is reported as an error by the Get... routines. In the latter case some of
  48. the elements of the value array will have been left untouched because the pixels
  49. they correspond to could not be accessed.
  50.  
  51. These routines (and RectToAddress) do not "move memory", i.e. they don't give
  52. the Memory Manager any pretext for shuffling around the memory allocations and
  53. changing its master pointers. That's why it's OK to dereference the pixmap handle,
  54. passing as an argument a temporary copy of the pixmap's master pointer.
  55.  
  56. SetPixmapPixelsQuickly and GetPixmapPixelsQuickly run fast by caching the
  57. information that they get about your Bit/Pixmap from RectToAddress. Set.. and
  58. Get.. each have their own cache. The cache is assumed to be fresh (i.e. is not
  59. recomputed) if it receives the same Pix/Bitmap as last time. It checks whether
  60. the pix/bitmap has the same address, baseAddr, rowBytes, and bounds. However, if
  61. the pix/bitmap has the same baseAddr as the mainDevice, yet actually corresponds
  62. to another device, then the cache is not used, because in a multi-screen
  63. environment QuickDraw associates all windows' pixmaps with the baseAddr of the
  64. main device (to create the illusion of a continuous desktop extending across
  65. multiple screens). You can force a flush of the cache by passing a NULL
  66. bit/pixmap pointer. (This will result in a returned value of 0, since the flush
  67. is always successful.)
  68.  
  69. See the demo Grating.c for an example of how to use this to display a pattern on
  70. the screen.
  71.  
  72.     // This is a simple write-then-read test of these routines,
  73.     // writing random numbers to the top line of the main screen.
  74.     unsigned long row[100],row2[100];
  75.     int rowLength=100,clutSize,i;
  76.     device=GetMainDevice();
  77.     clutSize=GDClutSize(device);
  78.     for(i=0;i<rowLength;i++)row[i]=nrand(clutSize);
  79.     SetDevicePixelsQuickly(device,0,0,row,rowLength);
  80.     GetDevicePixelsQuickly(device,0,0,row2,rowLength);
  81.     for(i=0;i<rowLength;i++)if(row2[i]!=row[i])
  82.         printf("%d-th pixel: wrote %ld, but read %ld\n",i,row[i],row2[i]);
  83.  
  84. WISHES:
  85. Mike Shadlen, shadlen@u.washington.edu, 
  86. "I often wish we could set the writing mode in setPixels. 
  87. Writing in xor mode is very useful."
  88. Sorry: it's a big job. You can always write to an offscreen
  89. window and CopyBits that to your final destination window
  90. using any writing mode.
  91.  
  92. HISTORY:
  93. 4/4/89     dgp wrote SetIPixel.c
  94. 9/8/90     dgp updated to work with 32 bit QuickDraw, if present.
  95. 10/15/90 bf renamed to SetIPixelGW.c and modified for drawing to off screen pix maps.
  96. 4/26/92     dgp Merged the two variants: SetIPixel.c and SetIPixelGW.c to produce the
  97.             new file SetOnePixel.c. Renamed existing routines to SetPixmapPixel,
  98.             GetPixmapPixel,SetDevicePixel,GetDevicePixel. Added SetOnePixel and 
  99.             GetOnePixel. Generalized to handle any pixelSize, and accept bitmaps as well
  100.             as pixmaps.
  101. 12/23/92 dgp Doubled the speed of SetPixmapPixel and GetPixmapPixel (and thus sped up
  102.             all the routines that call them) by caching the answers from RectToAddress. 
  103. 1/6/93 dgp    Fixed tiny but disastrous bug in GetPixmapPixel (wasn't saving old x and y).
  104. 1/22/93    dgp    Check more PixMap fields to make sure cache is not stale.
  105. 2/7/93    dgp Wrote SetPixelsQuickly.c
  106. 2/8/93    dgp Ironed out some wrinkles in the clipping.
  107. 4/27/93    dgp    Invalidate cache if baseAddr==mainDeviceBaseAddr.
  108. 6/4/93     dhb Modified to deal with MEX file weirdness in 24-bit mode.
  109.             These are all conditionally compiled in with the MATLAB
  110.             symbol. No intentional changes to original.
  111.         dgp    Here's my attempt to explain the problem and solution. 
  112.             MATLAB puts garbage in the high byte of the program counter register, 
  113.             so the machine crashes the instant you switch into 32-bit mode. 
  114.             The fix is to call a subroutine whose address has been cleaned by calling
  115.             StripAddress. This puts a 32-bit-clean address into the program counter,
  116.             until the subroutine returns. 
  117.         dhb The SwapMMUMode calls are arranged so that when MATLAB is defined only
  118.             a minimal amount of code is run in 32-bit mode.  The problem is that 
  119.             register A4, which is used in global addressing, also has garbage in
  120.             the high byte.  Not only is A4 used to reference globals, but as far
  121.             as I could tell, it is also used as an offset in certain code jumps. 
  122.             So if it is wrong, all hell breaks loose.  The solution is to run only
  123.             the code that blits the image in 32-bit mode.  I expect that this problem
  124.             will be fixed by a future version of MATLAB.
  125.         dgp    THINK C 5 sometimes implemented "switch" by a subroutine call, that might
  126.             explain the need to put the SwapMMUMode calls inside the switch, since
  127.             any subroutine call will fail when the global address register contains
  128.             garbage.
  129. 6/23/93    dgp Used THINK C preprocessor and MPW Compare to confirm that
  130.             code is unchanged when MATLAB is false.
  131. 7/9/93    dgp    Replaced calls to QD32Exists() by the variable can32, which is quicker,
  132.             and based on a more appropriate test: gestalt32BitCapable.
  133.             Test MATLAB in if() instead of #if. This is easier to read and
  134.             the compiler is smart enough to evaluate it at compile time so there's 
  135.             no runtime penalty.
  136. 4/11/94    dgp    In response to request from David Brainard, don't flush cache
  137.             when the pixmap truly refers to the main screen. Pixmaps for
  138.             screens other than the main screen still require a flush and call 
  139.             to RectToAddress in order to clip by the appropriate device bounds.
  140.             This wouldn't be necessary if we retained the old device or its
  141.             bounds, but unfortunately RectToAddress doesn't return them.
  142. 6/14/94    dgp    Discovered that TimeVideo crashed on Mac II with dirty ROMs. The
  143.             problem is that SetPixelsQuickly.c was naively
  144.             using the gestalt32BitCapable
  145.             bit to decide whether SwapMMUMode() was available, and this test
  146.             returns false when the ROMs are dirty (enabling MODE32 causes
  147.             the test to return true). Thus we were blithely skipping the
  148.             call to SwapMMUMode and trying to access 32-bit video addresses
  149.             in 24-bit mode. The correct test is to call
  150.             TrapAvailable(_SwapMMUMode). The test is now refined to call
  151.             SwapMMUMode only if we really need to.
  152. 10/26/94 dgp Changed GetWindowPixels and SetWindowPixels to use GetBitMapPtr, to
  153.             deal correctly with GWorldPtr, i.e. lock the pixels.
  154. 5/23/95 dgp Apple changed the prototype in the header file from SwapMMUMode(char *) to 
  155.             SwapMMUMode(signed char *). To retain compatibility with both old and new
  156.             headers, I cast the argument (void *).
  157. 6/7/95    dhb, gmb Weird MATLAB kluge only necessary if GENERATING68K.
  158. */
  159. #include "VideoToolbox.h"
  160. #ifndef __TRAPS__
  161.     #include <Traps.h>        // _SwapMMUMode
  162. #endif
  163. #define USE_CACHE 1    // set to zero to disable cache
  164. void ReadPixels(int x,int y,int n,unsigned long *value
  165.     ,unsigned char *baseAddr,long pixelSize,long rowBytes);
  166. void WritePixels(int x,int y,int n,unsigned long *value
  167.     ,unsigned char *baseAddr,long pixelSize,long rowBytes);
  168.  
  169. int SetPixelsQuickly(int x,int y,unsigned long value[],short n)
  170. // (x,y) is in the local coordinate system of the current port.
  171. {
  172.     WindowPtr window;
  173.  
  174.     GetPort(&window);
  175.     return SetWindowPixelsQuickly(window,x,y,value,n);
  176. }
  177.  
  178. int GetPixelsQuickly(int x,int y,unsigned long value[],short n)
  179. // (x,y) is in the local coordinate system of the current port.
  180. {
  181.     WindowPtr window;
  182.  
  183.     GetPort(&window);
  184.     return GetWindowPixelsQuickly(window,x,y,value,n);
  185. }
  186.  
  187. int SetWindowPixelsQuickly(WindowPtr window,int x,int y,unsigned long *value,short n)
  188. // (x,y) is in the local coordinate system of the window.
  189. // Accepts either WindowPtr or CWindowPtr.
  190. {
  191.     Rect r;
  192.     
  193.     if(window==NULL)return 1;
  194.     
  195.     // Clip to portRect.
  196.     SetRect(&r,x,y,x+n,y+1);
  197.     if(!SectRect(&window->portRect,&r,&r))return 0;
  198.     value+=r.left-x;
  199.     x=r.left;
  200.     n=r.right-r.left;
  201.     
  202.     return SetPixmapPixelsQuickly((PixMapPtr)GetBitMapPtr((CWindowPtr)window),x,y,value,n);
  203. }
  204.  
  205. int GetWindowPixelsQuickly(WindowPtr window,int x,int y,unsigned long *value,short n)
  206. // (x,y) is in the local coordinate system of the window.
  207. // Accepts WindowPtr, CWindowPtr, or GWorldPtr.
  208. {
  209.     int error=0;
  210.     Rect r;
  211.  
  212.     if(window==NULL)return 1;
  213.     
  214.     // Clip to portRect.
  215.     SetRect(&r,x,y,x+n,y+1);
  216.     if(!SectRect(&window->portRect,&r,&r))return 1;
  217.     if(x!=r.left || x+n!=r.right){    // Update after clipping.
  218.         error=1;
  219.         value+=r.left-x;
  220.         x=r.left;
  221.         n=r.right-r.left;
  222.     }
  223.     
  224.     error|=GetPixmapPixelsQuickly((PixMapPtr)GetBitMapPtr((CWindowPtr)window),x,y,value,n);
  225.     return error;
  226. }
  227.  
  228. int SetDevicePixelsQuickly(GDHandle device,int x,int y,unsigned long value[],short n)
  229. // (x,y) is relative to the upper left hand corner of the screen.
  230. {
  231.     Rect r;
  232.     
  233.     if(device==NULL)return 1;
  234.     x+=(*(*device)->gdPMap)->bounds.left;
  235.     y+=(*(*device)->gdPMap)->bounds.top;
  236.  
  237.     // Clip to device bounds.
  238.     SetRect(&r,x,y,x+n,y+1);
  239.     if(!SectRect(&(*(*device)->gdPMap)->bounds,&r,&r))return 0;
  240.     value+=r.left-x;    // Update after clipping.
  241.     x=r.left;
  242.     n=r.right-r.left;
  243.     
  244.     return SetPixmapPixelsQuickly(*(*device)->gdPMap,x,y,value,n);
  245. }
  246.  
  247. int GetDevicePixelsQuickly(GDHandle device,int x,int y,unsigned long value[],short n)
  248. // (x,y) is relative to the upper left hand corner of the screen.
  249. {
  250.     int error=1;
  251.     Rect r;
  252.     
  253.     if(device==NULL)return 1;
  254.     x+=(*(*device)->gdPMap)->bounds.left;
  255.     y+=(*(*device)->gdPMap)->bounds.top;
  256.     
  257.     // Clip to device bounds.
  258.     SetRect(&r,x,y,x+n,y+1);
  259.     if(!SectRect(&(*(*device)->gdPMap)->bounds,&r,&r))return 1;
  260.     if(x!=r.left || x+n!=r.right){    // Update after clipping.
  261.         error=1;
  262.         value+=r.left-x;
  263.         x=r.left;
  264.         n=r.right-r.left;
  265.     }
  266.     error|=GetPixmapPixelsQuickly(*(*device)->gdPMap,x,y,value,n);
  267.     return error;
  268. }
  269.  
  270. #if MATLAB && GENERATING68K
  271. int SetPixmapPixelsQuickly(PixMapPtr pmPtr,int x,int y,unsigned long value[]
  272.     ,register short n)
  273. {
  274.   int (*goSet) (PixMapPtr pmPtr,int x,int y,unsigned long value[],register short n);
  275.   int SPixmapPixelsQuickly(PixMapPtr pmPtr,int x,int y,unsigned long value[]
  276.       ,register short n);
  277.  
  278.   goSet = (void *) StripAddress(&SPixmapPixelsQuickly);
  279.   return( (*goSet) (pmPtr,x,y,value,n) );
  280. }
  281. static int SPixmapPixelsQuickly(PixMapPtr pmPtr,int x,int y,unsigned long value[]
  282.     ,register short n)
  283. #else
  284. int SetPixmapPixelsQuickly(PixMapPtr pmPtr,int x,int y,unsigned long value[]
  285.     ,register short n)
  286. #endif
  287. // Pokes a row of pixels. Accepts either pixmap or bitmap pointer.
  288. // (x,y) is in the coordinate system of the bit/pixmap.
  289. // Speed is enhanced by reusing the cached information from last time if it's the
  290. // same Pix/Bitmap as last time, i.e. same address, baseAddr, rowBytes, and bounds.
  291. // You can flush this cache by passing a NULL bit/pixmap pointer.
  292. {
  293.     static PixMapPtr oldPmPtr=(PixMapPtr)-1;
  294.     static int oldX,oldY;
  295.     static short rowBytes,logPixelSize,bitsOffset;
  296.     static unsigned char *pixelPtr;
  297.     static BitMap oldMap;
  298.     static Ptr mainBaseAddr=NULL;
  299.     static Boolean is32,can32,need32,firstTime=1;
  300.     signed char mode32=true32b;
  301.     int error=0;
  302.     Rect r;
  303.     long gestalt;
  304.     Boolean otherScreen;    // masquerading as extension of main screen
  305.     short pixelSize;
  306.     
  307.     if(firstTime){
  308.         Gestalt(gestaltAddressingModeAttr,&gestalt);
  309.         is32=gestalt&(1L<<gestalt32BitAddressing);
  310.         can32=TrapAvailable(_SwapMMUMode);
  311.         firstTime=0;
  312.     }
  313.     if(pmPtr==NULL){
  314.         oldPmPtr=(PixMapPtr)-1;    // invalidate cache
  315.         return 0;
  316.     }
  317.     // Clip to pix/bitmap bounds.
  318.     SetRect(&r,x,y,x+n,y+1);
  319.     if(mainBaseAddr==NULL){
  320.         if(QD8Exists())mainBaseAddr=(*(*GetMainDevice())->gdPMap)->baseAddr;
  321.         else mainBaseAddr=(void *)-1;
  322.     }
  323.     otherScreen= pmPtr->baseAddr==mainBaseAddr 
  324.         && (pmPtr->bounds.top!=0 || pmPtr->bounds.left!=0);
  325.     // Clip unless it's other screen.
  326.     if(!otherScreen)
  327.         if(!SectRect(&pmPtr->bounds,&r,&r))return 0;    // go home if we're done
  328.     if(!USE_CACHE
  329.         || otherScreen
  330.         || pmPtr!=oldPmPtr
  331.         || pmPtr->baseAddr!=oldMap.baseAddr 
  332.         || pmPtr->rowBytes!=oldMap.rowBytes 
  333.         || *(long *)&pmPtr->bounds.top!=*(long *)&oldMap.bounds.top
  334.         || *(long *)&pmPtr->bounds.bottom!=*(long *)&oldMap.bounds.bottom){
  335.         // Cache is stale. Get fresh values.
  336.         long value=0;
  337.         
  338.         // RectToAddress computes pixelPtr and clips r to the bit/pixmap bounds.
  339.         pixelPtr=RectToAddress(pmPtr,&r,&rowBytes,&pixelSize,&bitsOffset);
  340.         if(pixelPtr==NULL){
  341.             oldPmPtr=(PixMapPtr)-1;    // invalidate cache
  342.             return 0;
  343.         }
  344.         oldPmPtr=pmPtr;
  345.         oldMap=*(BitMap *)pmPtr;
  346.         logPixelSize=Log2L(pixelSize);
  347.         value+=r.left-x;    // Update after clipping.
  348.         x=r.left;
  349.         n=r.right-r.left;
  350.     }else{
  351.         // Cache is fresh. Merely correct for changes in x and y.
  352.         if(pixelPtr==NULL)return 1;
  353.         value+=r.left-x;    // Update after clipping.
  354.         x=r.left;
  355.         n=r.right-r.left;
  356.         if(x!=oldX){
  357.             if(logPixelSize<3){
  358.                 register long bits;
  359.                 bits=bitsOffset+(long)(x-oldX)<<logPixelSize;
  360.                 pixelPtr+=bits>>3;
  361.                 bitsOffset=bits&7;
  362.             }else pixelPtr+=(x-oldX)<<(logPixelSize-3);
  363.         }
  364.         if(y!=oldY)pixelPtr+=(long)(y-oldY)*rowBytes;
  365.     }
  366.     pixelSize=1<<logPixelSize;
  367.     WritePixels(bitsOffset/pixelSize,0,n,value,pixelPtr,pixelSize,rowBytes);
  368.     oldX=x;
  369.     oldY=y;
  370.     return error;
  371. }
  372.  
  373. #if MATLAB && GENERATING68K
  374. int GetPixmapPixelsQuickly(PixMapPtr pmPtr,int x,int y,unsigned long value[]
  375.     ,register short n)
  376. {
  377.   int (*goSet) (PixMapPtr pmPtr,int x,int y,unsigned long value[],register short n);
  378.   int GPixmapPixelsQuickly (PixMapPtr pmPtr,int x,int y,unsigned long value[],register short n);
  379.  
  380.   goSet = (void *) StripAddress(&GPixmapPixelsQuickly);
  381.   return( (*goSet) (pmPtr,x,y,value,n) );
  382. }
  383. static int GPixmapPixelsQuickly(PixMapPtr pmPtr,int x,int y,unsigned long value[]
  384.     ,register short n)
  385. #else
  386. int GetPixmapPixelsQuickly(PixMapPtr pmPtr,int x,int y,unsigned long value[]
  387.     ,register short n)
  388. #endif
  389. // Peeks a rows of pixels of any size. Accepts either pixmap or bitmap pointer.
  390. // (x,y) is in the coordinate system of the bit/pixmap.
  391. // Speed is enhanced by reusing the cached information from last time if it's the
  392. // same Pix/Bitmap as last time, i.e. same address, baseAddr,rowBytes, and bounds.
  393. // You can force it to flush its cache by passing a NULL bit/pixmap pointer.
  394. {
  395.     static PixMapPtr oldPmPtr=(PixMapPtr)-1;
  396.     static int oldX,oldY;
  397.     static short rowBytes,logPixelSize,bitsOffset;
  398.     static unsigned char *pixelPtr;
  399.     static BitMap oldMap;
  400.     static Ptr mainBaseAddr=NULL;
  401.     int error=0;
  402.     Rect r;
  403.     Boolean otherScreen;    // masquerading as extension of main screen
  404.     short pixelSize;
  405.     
  406.     if(pmPtr==NULL){
  407.         oldPmPtr=(PixMapPtr)-1;    // invalidate cache
  408.         return 0;
  409.     }
  410.     // Clip to pix/bitmap bounds.
  411.     SetRect(&r,x,y,x+n,y+1);
  412.     if(mainBaseAddr==NULL){
  413.         if(QD8Exists())mainBaseAddr=(*(*GetMainDevice())->gdPMap)->baseAddr;
  414.         else mainBaseAddr=(void *)-1;
  415.     }
  416.     otherScreen= pmPtr->baseAddr==mainBaseAddr 
  417.         && (pmPtr->bounds.top!=0 || pmPtr->bounds.left!=0);
  418.     // Clip unless it's other screen.
  419.     if(!otherScreen)
  420.         if(!SectRect(&pmPtr->bounds,&r,&r))return 1;    // go home if we're done
  421.     if(!USE_CACHE
  422.         || otherScreen
  423.         || pmPtr!=oldPmPtr
  424.         || pmPtr->baseAddr!=oldMap.baseAddr 
  425.         || pmPtr->rowBytes!=oldMap.rowBytes 
  426.         || *(long *)&pmPtr->bounds.top!=*(long *)&oldMap.bounds.top
  427.         || *(long *)&pmPtr->bounds.bottom!=*(long *)&oldMap.bounds.bottom){
  428.         // Cache is stale. Get fresh values.
  429.         long value=0;
  430.  
  431.         // RectToAddress computes pixelPtr and clips r to the bit/pixmap bounds.
  432.         pixelPtr=RectToAddress(pmPtr,&r,&rowBytes,&pixelSize,&bitsOffset);
  433.         if(pixelPtr==NULL){
  434.             oldPmPtr=(PixMapPtr)-1;    // invalidate cache
  435.             return 0;
  436.         }
  437.         oldPmPtr=pmPtr;
  438.         oldMap=*(BitMap *)pmPtr;
  439.         logPixelSize=Log2L(pixelSize);
  440.         if(x!=r.left || x+n!=r.right){    // Update after clipping.
  441.             error=1;
  442.             value+=r.left-x;
  443.             x=r.left;
  444.             n=r.right-r.left;
  445.         }
  446.     }else{
  447.         // Cache is fresh. Merely correct for changes in x and y.
  448.         if(pixelPtr==NULL)return 1;
  449.         if(x!=r.left || x+n!=r.right){    // Update after clipping.
  450.             error=1;
  451.             value+=r.left-x;
  452.             x=r.left;
  453.             n=r.right-r.left;
  454.         }
  455.         if(x!=oldX){
  456.             if(logPixelSize<3){
  457.                 register long bits;
  458.                 bits=bitsOffset+(long)(x-oldX)<<logPixelSize;
  459.                 pixelPtr+=bits>>3;
  460.                 bitsOffset=bits&7;
  461.             }else pixelPtr+=(x-oldX)<<(logPixelSize-3);
  462.         }
  463.         if(y!=oldY)pixelPtr+=(long)(y-oldY)*rowBytes;
  464.     }
  465.     pixelSize=1<<logPixelSize;
  466.     ReadPixels(bitsOffset/pixelSize,0,n,value,pixelPtr,pixelSize,rowBytes);
  467.     oldX=x;
  468.     oldY=y;
  469.     return error;
  470. }
  471.  
  472. // Fast access to pixels, with no overhead
  473. void WritePixels(int x,int y,int n,unsigned long *value
  474.     ,unsigned char *baseAddr,long pixelSize,long rowBytes)
  475. {
  476.     static Boolean can32,is32,firstTime=1;
  477.     Boolean need32;
  478.     signed char mode32=true32b;
  479.     short bitsOffset=0;
  480.     unsigned char *pixelPtr=baseAddr;
  481.     int shift;
  482.  
  483.     if(firstTime){
  484.         long gestalt;
  485.         can32=TrapAvailable(_SwapMMUMode);
  486.         Gestalt(gestaltAddressingModeAttr,&gestalt);
  487.         is32=gestalt&(1L<<gestalt32BitAddressing);
  488.         firstTime=0;
  489.     }
  490.     if(x!=0){
  491.             register long bits;
  492.  
  493.             bits=x*pixelSize;
  494.             pixelPtr+=bits>>3;
  495.             bitsOffset=bits&7;
  496.     }
  497.     if(y!=0)pixelPtr+=y*rowBytes;
  498.     need32=(unsigned long)pixelPtr>0xffffffUL;
  499.     if(need32 && !can32)PrintfExit("%s line %d: 32 bit address in 24 bit computer.\n"
  500.         ,__FILE__,__LINE__);
  501.     need32=need32 && !is32;
  502.     switch(pixelSize){
  503.     case 1:{
  504.         register unsigned char val,mask,*ptr=pixelPtr;
  505.         shift=sizeof(*ptr)*8;
  506.         shift-=bitsOffset;    // from right, instead of from left
  507.         if(need32)SwapMMUMode((void *)&mode32);
  508.         do{
  509.             val=mask=0;
  510.             do{
  511.                 shift-=1;
  512.                 val<<=1;
  513.                 mask<<=1;
  514.                 if(n>0){
  515.                     val|=(*value++)&1;
  516.                     mask|=1;
  517.                     n--;
  518.                 }else{
  519.                     val<<=shift;
  520.                     mask<<=shift;
  521.                     break;
  522.                 }
  523.             }while(shift>0);
  524.             mask=~mask;
  525.             *ptr= *ptr & mask | (unsigned char)val;
  526.             ptr++;
  527.             shift=sizeof(*ptr)*8;
  528.         }while(n>0);
  529.         if(need32)SwapMMUMode((void *)&mode32);
  530.         break;
  531.     }
  532.     case 2:{
  533.         register unsigned char val,mask,*ptr=pixelPtr;
  534.         shift=sizeof(*ptr)*8;
  535.         shift-=bitsOffset;    // from right, instead of from left
  536.         if(need32)SwapMMUMode((void *)&mode32);
  537.         do{
  538.             val=mask=0;
  539.             do{
  540.                 shift-=2;
  541.                 val<<=2;
  542.                 mask<<=2;
  543.                 if(n>0){
  544.                     val|=(*value++)&3;
  545.                     mask|=3;
  546.                     n--;
  547.                 }else{
  548.                     val<<=shift;
  549.                     mask<<=shift;
  550.                     break;
  551.                 }
  552.             }while(shift>0);
  553.             mask=~mask;
  554.             *ptr= *ptr & mask | (unsigned char)val;
  555.             ptr++;
  556.             shift=sizeof(*ptr)*8;
  557.         }while(n>0);
  558.         if(need32)SwapMMUMode((void *)&mode32);
  559.         break;
  560.     }
  561.     case 4:{
  562.         register unsigned char val,mask,*ptr=pixelPtr;
  563.         shift=sizeof(*ptr)*8;
  564.         shift-=bitsOffset;    // from right, instead of from left
  565.         if(need32)SwapMMUMode((void *)&mode32);
  566.         do{
  567.             val=mask=0;
  568.             do{
  569.                 shift-=4;
  570.                 val<<=4;
  571.                 mask<<=4;
  572.                 if(n>0){
  573.                     val|=(*value++)&15;
  574.                     mask|=15;
  575.                     n--;
  576.                 }else{
  577.                     val<<=shift;
  578.                     mask<<=shift;
  579.                     break;
  580.                 }
  581.             }while(shift>0);
  582.             mask=~mask;
  583.             *ptr= *ptr & mask | (unsigned char)val;
  584.             ptr++;
  585.             shift=sizeof(*ptr)*8;
  586.         }while(n>0);
  587.         if(need32)SwapMMUMode((void *)&mode32);
  588.         break;
  589.     }
  590.     case 8:{
  591.         register unsigned char *pB=pixelPtr;
  592.         if(need32)SwapMMUMode((void *)&mode32);
  593.         for(;n>0;n--) *pB++ = *value++;
  594.         if(need32)SwapMMUMode((void *)&mode32);
  595.         break;
  596.     }
  597.     case 16:{
  598.         register unsigned short *pW=(unsigned short *)pixelPtr;
  599.         if(need32)SwapMMUMode((void *)&mode32);
  600.         for(;n>0;n--) *pW++ = *value++;
  601.         if(need32)SwapMMUMode((void *)&mode32);
  602.         break;
  603.     }
  604.     case 32:{
  605.         register unsigned long *pL=(unsigned long *)pixelPtr;
  606.         if(need32)SwapMMUMode((void *)&mode32);
  607.         for(;n>0;n--) *pL++ = *value++;
  608.         if(need32)SwapMMUMode((void *)&mode32);
  609.         break;
  610.     }
  611.     }
  612. }
  613.  
  614. // Fast access to pixels, with no overhead
  615. void ReadPixels(int x,int y,int n,unsigned long *value
  616.     ,unsigned char *baseAddr,long pixelSize,long rowBytes)
  617. {
  618.     static Boolean can32,is32,firstTime=1;
  619.     Boolean need32;
  620.     signed char mode32=true32b;
  621.     short bitsOffset=0;
  622.     unsigned char *pixelPtr=baseAddr;
  623.     int shift;
  624.  
  625.     if(firstTime){
  626.         long gestalt;
  627.         can32=TrapAvailable(_SwapMMUMode);
  628.         Gestalt(gestaltAddressingModeAttr,&gestalt);
  629.         is32=gestalt&(1L<<gestalt32BitAddressing);
  630.         firstTime=0;
  631.     }
  632.     if(x!=0){
  633.             register long bits;
  634.  
  635.             bits=x*pixelSize;
  636.             pixelPtr+=bits>>3;
  637.             bitsOffset=bits&7;
  638.     }
  639.     if(y!=0)pixelPtr+=y*rowBytes;
  640.     need32=(unsigned long)pixelPtr>0xffffffUL;
  641.     if(need32 && !can32)PrintfExit("%s line %d: 32 bit address in 24 bit computer.\n"
  642.         ,__FILE__,__LINE__);
  643.     need32=need32 && !is32;
  644.     switch(pixelSize){
  645.     case 1:{
  646.         register unsigned char val,*ptr=pixelPtr;
  647.         shift=sizeof(*ptr)*8;
  648.         shift-=bitsOffset;    // from right, instead of from left
  649.         if(need32)SwapMMUMode((void *)&mode32);
  650.         do{
  651.             val=*ptr++;
  652.             do{
  653.                 shift-=1;
  654.                 if(n>0){
  655.                     *value++=(val>>shift)&1;
  656.                     n--;
  657.                 }else{
  658.                     break;
  659.                 }
  660.             }while(shift>0);
  661.             shift=sizeof(*ptr)*8;
  662.         }while(n>0);
  663.         if(need32)SwapMMUMode((void *)&mode32);
  664.         break;
  665.     }
  666.     case 2:{
  667.         register unsigned char val,*ptr=pixelPtr;
  668.         shift=sizeof(*ptr)*8;
  669.         shift-=bitsOffset;    // from right, instead of from left
  670.         if(need32)SwapMMUMode((void *)&mode32);
  671.         do{
  672.             val=*ptr++;
  673.             do{
  674.                 shift-=2;
  675.                 if(n>0){
  676.                     *value++=(val>>shift)&3;
  677.                     n--;
  678.                 }else{
  679.                     break;
  680.                 }
  681.             }while(shift>0);
  682.             shift=sizeof(*ptr)*8;
  683.         }while(n>0);
  684.         if(need32)SwapMMUMode((void *)&mode32);
  685.         break;
  686.     }
  687.     case 4:{
  688.         register unsigned char val,*ptr=pixelPtr;
  689.         shift=sizeof(*ptr)*8;
  690.         shift-=bitsOffset;    // from right, instead of from left
  691.         if(need32)SwapMMUMode((void *)&mode32);
  692.         do{
  693.             val=*ptr++;
  694.             do{
  695.                 shift-=4;
  696.                 if(n>0){
  697.                     *value++=(val>>shift)&15;
  698.                     n--;
  699.                 }else{
  700.                     break;
  701.                 }
  702.             }while(shift>0);
  703.             shift=sizeof(*ptr)*8;
  704.         }while(n>0);
  705.         if(need32)SwapMMUMode((void *)&mode32);
  706.         break;
  707.     }
  708.     case 8:{
  709.         register unsigned char *pB=pixelPtr;
  710.         if(need32)SwapMMUMode((void *)&mode32);
  711.         for(;n>0;n--) *value++=*pB++;
  712.         if(need32)SwapMMUMode((void *)&mode32);
  713.         break;
  714.     }
  715.     case 16:{
  716.         register unsigned short *pW=(unsigned short *)pixelPtr;
  717.         if(need32)SwapMMUMode((void *)&mode32);
  718.         for(;n>0;n--) *value++=*pW++;
  719.         if(need32)SwapMMUMode((void *)&mode32);
  720.         break;
  721.     }
  722.     case 32:{
  723.         register unsigned long *pL=(unsigned long *)pixelPtr;
  724.         if(need32)SwapMMUMode((void *)&mode32);
  725.         for(;n>0;n--) *value++=*pL++;
  726.         if(need32)SwapMMUMode((void *)&mode32);
  727.         break;
  728.     }
  729.     }
  730. }
  731.